import json
from channels.generic.websocket import AsyncWebsocketConsumer
from django.db.models import Q
from .models import Conversation, Message, ConversationParticipant, UserStatus
from django.utils import timezone
from accounts.jwt_utils import jwt_required, decode_jwt_token
from accounts.models import Student, Teacher
import logging

# 配置日志记录
logger = logging.getLogger(__name__)

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        try:
            self.conversation_id = self.scope['url_route']['kwargs']['conversation_id']
            logger.info(f"-----进入connect方法，会话ID: {self.conversation_id}")
            self.group_name = f'chat_{self.conversation_id}'
            logger.info(f"-------已定义group_name: {self.group_name}")

            try:
                logger.debug(f"[DEBUG] 尝试获取会话: {self.conversation_id}")
                self.conversation = await Conversation.objects.aget(id=self.conversation_id)
                logger.debug(f"[DEBUG] 成功获取会话: {self.conversation}")
            except Conversation.DoesNotExist:
                logger.warning(f"[WARNING] 会话 {self.conversation_id} 不存在")
                await self.close()
                return

            # 提取JWT令牌
            token = self.extract_token()
            if not token:
                logger.warning("[WARNING] 未提供JWT认证令牌")
                await self.close(code=4001)

                # 解码并验证JWT令牌（使用accounts.jwt_utils.decode_jwt_token）
            try:
                payload = decode_jwt_token(token)
                self.user_id = payload.get('user_id')
                self.user_type = payload.get('user_type')  # 'student' 或 'teacher'

                if not all([self.user_id, self.user_type]):
                    raise ValueError("JWT令牌缺少用户关键信息")
                if self.user_type == 'student':
                    self.user = await Student.objects.aget(id=self.user_id)
                elif self.user_type == 'teacher':
                    self.user = await Teacher.objects.aget(id=self.user_id)
                logger.debug(f"[DEBUG] JWT验证成功，用户ID: {self.user_id}, 类型: {self.user_type}")
            except Exception as e:
                logger.warning(f"[WARNING] JWT令牌验证失败: {str(e)}")
                await self.close(code=4001)
                return

            # 检查用户是否是会话参与者
            logger.debug("[DEBUG] 检查用户是否是会话参与者")
            participant = await ConversationParticipant.objects.filter(
                Q(student=self.user_id, user_type='student') |
                Q(teacher=self.user_id, user_type='teacher'),
                conversation=self.conversation
            ).afirst()

            if not participant:
                logger.warning("[WARNING] 用户不是会话参与者，拒绝连接")
                await self.close(code=4003)
                return
            logger.debug("[DEBUG] 用户是会话参与者，允许连接")

            # 设置用户为在线状态
            logger.debug("[DEBUG] 设置用户为在线状态")
            await self.update_user_status(True)

            # 加入会话组
            logger.debug(f"[DEBUG] 加入会话组: {self.group_name}")
            await self.channel_layer.group_add(
                self.group_name,
                self.channel_name
            )

            # 接受连接
            logger.debug("[DEBUG] 接受WebSocket连接")
            await self.accept()

            # 标记所有消息为已读
            logger.debug("[DEBUG] 标记会话消息为已读")
            await self.mark_messages_as_read()

            # 发送加入通知
            logger.debug("[DEBUG] 发送用户加入通知")
            await self.channel_layer.group_send(
                self.group_name,
                {
                    'type': 'user.join',
                    'user_id': self.get_user_id(),
                    'username': self.get_username(),
                    'user_type': self.user_type,
                    'time': timezone.now().strftime('%Y-%m-%d %H:%M:%S')
                }
            )
            logger.info(f"[INFO] 用户 {self.get_username()} 已加入会话 {self.conversation_id}")
        except Exception as e:
            logger.error(f"[ERROR] 连接处理过程中发生异常: {str(e)}", exc_info=True)
            await self.close()

    async def disconnect(self, close_code):
        try:
            logger.debug(f"[DEBUG] 进入disconnect方法，关闭代码: {close_code}")
            # 从会话组中移除（添加存在性检查）
            if hasattr(self, 'group_name'):
                logger.debug(f"[DEBUG] 从组 {self.group_name} 中移除")
                await self.channel_layer.group_discard(
                    self.group_name,
                    self.channel_name
                )

            # 设置用户为离线状态
            logger.debug("[DEBUG] 设置用户为离线状态")
            await self.update_user_status(False)

            # 发送离开通知（添加存在性检查）
            if hasattr(self, 'group_name'):
                logger.debug(f"[DEBUG] 发送离开通知到组 {self.group_name}")
                await self.channel_layer.group_send(
                    self.group_name,
                    {
                        'type': 'user.leave',
                        'user_id': self.get_user_id(),
                        'username': self.get_username(),
                        'user_type': self.user_type,
                        'time': timezone.now().strftime('%Y-%m-%d %H:%M:%S')
                    }
                )
            logger.info(f"[INFO] 用户 {self.get_username()} 已离开会话 {self.conversation_id}")
        except Exception as e:
            logger.error(f"[ERROR] 断开连接处理过程中发生异常: {str(e)}", exc_info=True)

    async def receive(self, text_data):
        try:
            logger.debug(f"[DEBUG] 收到客户端消息: {text_data}")
            text_data_json = json.loads(text_data)
            message_type = text_data_json.get('type')
            logger.debug(f"[DEBUG] 消息类型: {message_type}")

            if message_type == 'message':
                # 处理普通消息
                content = text_data_json.get('content')
                logger.debug(f"[DEBUG] 处理消息内容: {content}")
                await self.send_message(content)
            elif message_type == 'typing':
                # 处理输入状态
                logger.debug("[DEBUG] 处理输入状态通知")
                await self.channel_layer.group_send(
                    self.group_name,
                    {
                        'type': 'user.typing',
                        'user_id': self.get_user_id(),
                        'username': self.get_username(),
                        'user_type': self.user_type
                    }
                )
        except json.JSONDecodeError:
            logger.error("[ERROR] 收到无效的JSON消息")
        except Exception as e:
            logger.error(f"[ERROR] 处理消息时发生错误: {e}", exc_info=True)

    async def send_message(self, content):
        try:
            logger.debug(f"[DEBUG] 准备发送消息: {content}")
            # 创建消息记录
            message = await self.create_message(content)
            logger.debug(f"[DEBUG] 已创建消息，ID: {message.id}")

            # 发送消息到会话组
            logger.debug(f"[DEBUG] 向组 {self.group_name} 发送消息")
            await self.channel_layer.group_send(
                self.group_name,
                {
                    'type': 'chat.message',
                    'id': str(message.id),
                    'sender_id': self.get_user_id(),
                    'sender_username': self.get_username(),
                    'content': content,
                    'time': message.created_at.strftime('%Y-%m-%d %H:%M:%S'),
                    'sender_type': self.user_type
                }
            )
        except Exception as e:
            logger.error(f"[ERROR] 发送消息时发生错误: {e}", exc_info=True)

    async def chat_message(self, event):
        try:
            logger.debug(f"[DEBUG] 收到组消息: {event}")
            # 发送消息到客户端
            await self.send(text_data=json.dumps({
                'type': 'message',
                'id': event['id'],
                'sender_id': event['sender_id'],
                'sender_username': event['sender_username'],
                'content': event['content'],
                'time': event['time'],
                'sender_type': event['sender_type']
            }))
            logger.debug(f"[DEBUG] 已向客户端发送消息: {event['content'][:20]}...")
        except Exception as e:
            logger.error(f"[ERROR] 处理组消息时发生错误: {e}", exc_info=True)

    async def user_join(self, event):
        try:
            logger.debug(f"[DEBUG] 收到用户加入通知: {event}")
            # 发送用户加入通知
            await self.send(text_data=json.dumps({
                'type': 'user_join',
                'user_id': event['user_id'],
                'username': event['username'],
                'user_type': event['user_type'],
                'time': event['time']
            }))
            logger.info(f"[INFO] 用户 {event['username']} 加入会话")
        except Exception as e:
            logger.error(f"[ERROR] 处理用户加入通知时发生错误: {e}", exc_info=True)

    async def user_leave(self, event):
        try:
            logger.debug(f"[DEBUG] 收到用户离开通知: {event}")
            # 发送用户离开通知
            await self.send(text_data=json.dumps({
                'type': 'user_leave',
                'user_id': event['user_id'],
                'username': event['username'],
                'user_type': event['user_type'],
                'time': event['time']
            }))
            logger.info(f"[INFO] 用户 {event['username']} 离开会话")
        except Exception as e:
            logger.error(f"[ERROR] 处理用户离开通知时发生错误: {e}", exc_info=True)

    async def user_typing(self, event):
        try:
            logger.debug(f"[DEBUG] 收到用户输入状态: {event}")
            # 发送用户输入状态
            await self.send(text_data=json.dumps({
                'type': 'user_typing',
                'user_id': event['user_id'],
                'username': event['username'],
                'user_type': event['user_type']
            }))
        except Exception as e:
            logger.error(f"[ERROR] 处理用户输入状态时发生错误: {e}", exc_info=True)

    def get_user_id(self):
        """获取用户ID"""
        if self.user_type == 'student':
            return self.user.id
        return self.user.id

    def get_username(self):
        """获取用户名"""
        if self.user_type == 'student':
            return self.user.name
        return self.user.name


    # 配置日志记录
    logger = logging.getLogger(__name__)

    def extract_token(self):
        """从请求中提取JWT令牌（支持查询参数和HTTP头）"""
        # 从查询参数提取（如：ws://example.com/chat/1/?token=xxx）
        query_string = self.scope.get('query_string', b'').decode('utf-8')
        for param in query_string.split('&'):
            if param.startswith('token='):
                return param.split('=', 1)[1]

        # 从HTTP头提取（支持Bearer格式，如：Authorization: Bearer xxx）
        headers = dict(self.scope.get('headers', []))
        if b'authorization' in headers:
            auth_header = headers[b'authorization'].decode('utf-8')
            if auth_header.startswith('Bearer '):
                return auth_header.split(' ', 1)[1]

        return None

    async def update_user_status(self, is_online):
        """更新用户在线状态"""
        status_text = "在线" if is_online else "离线"
        logger.debug(f"[DEBUG] 更新用户状态为: {status_text}")
        try:
            if self.user_type == 'student':
                status = await UserStatus.objects.aget(student=self.user)
            else:
                status = await UserStatus.objects.aget(teacher=self.user)

            status.is_online = is_online
            status.last_seen = timezone.now()
            await status.asave()
            logger.debug(f"[DEBUG] 已更新用户状态: {status}")
        except UserStatus.DoesNotExist:
            # 如果状态不存在，创建一个新的
            logger.debug("[DEBUG] 用户状态不存在，创建新状态")
            if self.user_type == 'student':
                await UserStatus.objects.acreate(
                    student=self.user,
                    user_type='student',
                    is_online=is_online,
                    last_seen=timezone.now()
                )
            else:
                await UserStatus.objects.acreate(
                    teacher=self.user,
                    user_type='teacher',
                    is_online=is_online,
                    last_seen=timezone.now()
                )
            logger.info(f"[INFO] 已创建新用户状态: {self.user_type}, {status_text}")
        except Exception as e:
            logger.error(f"[ERROR] 更新用户状态时发生错误: {e}", exc_info=True)

    async def mark_messages_as_read(self):
        """标记会话中的消息为已读"""
        logger.debug("[DEBUG] 开始标记消息为已读")
        try:
            if self.user_type == 'student':
                participant = await ConversationParticipant.objects.aget(
                    conversation=self.conversation,
                    student=self.user,
                    user_type='student'
                )
            else:
                participant = await ConversationParticipant.objects.aget(
                    conversation=self.conversation,
                    teacher=self.user,
                    user_type='teacher'
                )

            # 标记消息为已读的代码...
            # 注意：你的原始代码在这里不完整，需要补充完整的标记消息为已读的逻辑
            logger.debug("[DEBUG] 消息标记为已读完成")
        except ConversationParticipant.DoesNotExist:
            logger.warning("[WARNING] 未找到会话参与者记录")
        except Exception as e:
            logger.error(f"[ERROR] 标记消息为已读时发生错误: {e}", exc_info=True)

    async def create_message(self, content):
        """创建消息记录"""
        # 注意：你的原始代码中缺少这个方法的实现
        logger.info(f"[info] 创建一条消息(会话): {self.conversation}", exc_info=True)
        # 这里提供一个简单的实现，你可能需要根据你的模型调整
        if self.user_type == 'student':
            message = await Message.objects.acreate(
                conversation=self.conversation,
                sender_student=self.user,
                content=content
            )
        else:
            message = await Message.objects.acreate(
                conversation=self.conversation,
                sender_teacher=self.user,
                content=content
            )
        logger.info(f"[info] 保存消息，查看消息: {message}", exc_info=True)
        return message